﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////

#pragma once

#include "GcmpModelInterface.h"
#include "IExternalObject.h"
#include "NdbDataSchema.h"
#include "GbmpQuickCast.h"
#include "ElementCreationOptions.h"
#include "IGraphicsRichText.h"
#include "IGraphicsElementShape.h"

namespace gcmp
{
    class IDocument;
    class IDrawingTableItemEvent;

    /// \brief 表格中文字流向
    SERIALIZABLE_ENUM_CLASS(TextDirection)
    {
        FollowTableCoordinate3dX = 0,             ///< 文字流向随表格流向，即表格工作坐标系X方向
        FollowTableCoordinate3dY = 1,             ///< 文字流向随表格工作坐标系Y方向
        FollowTableCoordinate3dNegativeY = 2      ///< 文字流向随表格工作坐标系-Y方向
    };

    /// \brief 单元格图例参考位置定义
    SERIALIZABLE_ENUM_CLASS(RelatedElementReferencePointType)
    {
        LeftTop = 0,
        LeftBottom = 1,
        RightBottom = 2,
        RightTop = 3
    };

    /// \brief 单元格外边线类型
    SERIALIZABLE_ENUM_CLASS(TableItemOutLineType)
    {
        All = -1,           ///< 所有边，左、上、右、下
        Left = 0,           ///< 左边
        Right = 1,          ///< 右边
        Top = 2,            ///< 上边
        Bottom = 3          ///< 下边
    };

    /// \brief 单元格相对于表格的index信息
    struct GCMP_MODEL_INTERFACE_EXPORT TableItemIndex
    {
    public:
        TableItemIndex(Int16 nPage, Int16 nRow, Int16 nCol);
        TableItemIndex();
        bool IsValidIndex() const;      //是否有效的index
        bool operator < (const struct TableItemIndex & right) const;   //重载<运算符
        bool operator != (const struct TableItemIndex & right) const;   //重载!=运算符
        bool operator == (const struct TableItemIndex& right) const;   //重载==运算符
    public:
        Int16 m_nPage;       //页码
        Int16 m_nRow;        //行
        Int16 m_nCol;        //列
    };

    struct GCMP_MODEL_INTERFACE_EXPORT TableTextStyle
    {
        TableTextStyle();
    public:
        double m_CharHeight;
        double m_LineSpaceScale;
        double m_CharacterSpace;
        double m_CharWidthFactor;
        bool m_IsTextBold;
        bool m_IsTextItalic;
        bool m_IsTextUnderLine;
        bool m_IsAutoWrap;
        VerticalAlignmentType m_TextVerticalAlignType;
        HorizontalAlignmentType m_TextHorizontalAlignType;
        std::wstring m_TextFont;        ///< 文字字体(文件)名,非空时m_ChineseFont、m_EnglishFont应为空
        std::wstring m_TextBigFont;     ///< 大字体(文件)名,非空时m_ChineseFont、m_EnglishFont应为空
        gcmp::ElementId m_TextStyleId;
        std::wstring m_ChineseFont;     ///< 中文字符字体(文件)名,非空时m_TextFont、m_TextBigFont应为空
        std::wstring m_EnglishFont;     ///< 西文字符字体(文件)名，非空时m_TextFont、m_TextBigFont应为空
    };

    /// \brief  表格元素（单元格）接口类
    ///
    class GCMP_MODEL_INTERFACE_EXPORT IDrawingTableItem  : public IExternalObject
    {
        DEFINE_CAST_DERIVED(gcmp::IDrawingTableItem, gcmp::IExternalObject);
    public:
        virtual ~IDrawingTableItem();
    public:
        /// \brief 是否为表头
        ///
        /// \return bool true表头  false非表头
        virtual bool IsHeader() const = 0;

        /// \brief 获取自定义比例
        ///
        /// \return double 比例值（ 大于 0 ）
        virtual double GetScale() const = 0;

        /// \brief 获取单元格的坐标系
        ///
        /// \return Coordinate3d 坐标系
        virtual Coordinate3d GetCoordinate3d() const = 0;

        /// \brief 获取单元格acad样式字符串
        ///
        /// \return wstring 返回acad样式字符串
        virtual const std::wstring& GetText() const = 0;

        /// \brief 设置单元格acad样式字符串
        ///
        /// IsTextReadOnly()为true，即文本只读时设置文本内容会失败
        /// \param sText acad 样式字符串
        /// \return bool true表示设置成功，否则设置失败
        virtual bool SetText(const std::wstring& sText) = 0;

        /// \brief 设置单元格文字样式
        /// 一次性设置单元格文字样式所有属性
        /// \return bool true表示设置成功，否则设置失败
        virtual bool SetTextStyle(const TableTextStyle& textStyle) = 0;

        /// \brief 获取单元格所在列的宽度
        ///
        /// 与通过自身单元格在所属表中的index,使用IDrawingTable::GetColumnWidth(index)高度值效果一致。
        /// 使用可参照https://km.glodon.com/pages/viewpage.action?pageId=379559666
        /// \return double 宽度值
        virtual double GetWidth() const = 0;


        /// \brief 获取单元格所在行的高度
        ///
        /// 与通过自身单元格在所属表中的index,使用IDrawingTable::GetRowHeight(index)高度值效果一致。
        /// 使用可参照https://km.glodon.com/pages/viewpage.action?pageId=379559666
        /// \return double 高度值
        virtual double GetHeight() const = 0;

        
        /// \brief 获取单元格左上角世界坐标
        ///
        /// \return Vector3d  单元格左上角世界坐标
        virtual Vector3d GetPosition() const = 0;


        /// \brief 获取文字字符高度
        ///
        /// \return double  字符高度值
        virtual double GetCharHeight() const = 0;

        /// \brief 设置文字字符高度
        ///
        /// \param textHeight 字符高度值
        /// \return bool  true表示设置成功，否则设置失败
        virtual bool SetCharHeight(double textHeight) = 0;

        /// \brief 设置单元格文本内容是否为只读
        ///
        /// \param isReadOnly 单元格文本是否只读
        /// \return bool  true表示设置成功，否则设置失败
        virtual bool SetTextReadOnly(bool isReadOnly) = 0;

        /// \brief 获取单元格文本内容是否只读
        ///
        /// 如果关联了图例，单元格文本为只读,用户设置为可编辑将会设置失败
        /// \return bool true只读  false可编辑
        /// \return bool  true表示设置成功，否则设置失败
        virtual bool IsTextReadOnly() const = 0;

        /// \brief 设置单元格文本可见性
        ///
        /// 如果关联了图例，单元格文本为不可见，用户设置文本可见将会设置失败
        /// \param isVisible true可见  false不可见
        /// \return bool  true表示设置成功，否则设置失败
        virtual bool SetTextVisibility(bool isVisible) = 0;

        /// \brief 获取单元格文本可见性
        ///
        /// \param bool true可见  false不可见
        virtual bool IsTextVisibility() const = 0;

        /// \biref 设置水平对齐方式
        ///
        /// HorizontalAlignmentType::Scatter 分散对齐在非文本自动换行的情况下情况下才有效果
        /// \param horizontalAlignment 水平对齐方式(默认水平居中对齐)
        /// \return bool true表示设置成功，否则设置失败
        virtual bool SetTextHorizontalAlignmentType(HorizontalAlignmentType horizontalAlignment) = 0;

        /// \brief 获取水平对齐方式
        ///
        /// \return 返回水平对齐方式
        virtual HorizontalAlignmentType GetTextHorizontalAlignmentType() const = 0;

        /// \biref 设置竖直对齐方式
        ///
        /// \param verticalAlignment 竖直对齐方式(默认竖直居中对齐)
        /// \return bool true表示设置成功，否则设置失败
        virtual bool SetTextVerticalAlignmentType(VerticalAlignmentType verticalAlignment) = 0;

        /// \brief 获取竖直对齐方式
        ///
        /// \return 返回竖直对齐方式
        virtual VerticalAlignmentType GetTextVerticalAlignmentType() const = 0;

        /// \brief 设置文字自动换行
        ///
        /// \param isAutoWrap  true换行  false不换行
        /// \return bool true表示设置成功，否则设置失败
        virtual bool SetTextAutoWrap(bool isAutoWrap) = 0;

        /// \brief 获得文字是否自动换行
        ///
        /// \return 返回是否自动换行
        virtual bool IsTextAutoWrap() const = 0;

        /// \brief 设置文字字体加粗
        ///
        /// \param isBold  true粗体  false正常（默认正常不加粗）
        /// \return bool true表示设置成功，否则设置失败
        virtual bool SetTextBold(bool isBold) = 0;

        /// \brief 获得文字字体是否加粗
        ///
        /// \return 返回字体是否加粗
        virtual bool IsTextBold() const = 0;

        /// \brief 字体斜体
        ///
        /// \param isItalic  true斜体  false正常(默认正常)
        /// \return bool true表示设置成功，否则设置失败
        virtual bool SetTextItalic(bool isItalic) = 0;

        /// \brief 字体缺省是否斜体
        ///
        /// \return 返回字体是否斜体
        virtual bool IsTextItalic() const = 0;

        /// \brief 字体添加下划线
        ///
        /// \param isUnderLine  true带下划线  false正常（默认正常不带下划线）
        /// \return bool true表示设置成功，否则设置失败
        virtual bool SetTextUnderLine(bool isUnderLine) = 0;

        /// \brief 字体整体是否添加下划线
        ///
        /// \return true表示添加下划线
        virtual bool IsTextUnderLine() const = 0;

        /// \brief 设置字体文件名或字体名
        ///
        /// SetTextFont()与SetTextBigFont()可结对使用，SetEnglishAndChineseCharFont()单独使用，在使用的时候建议将另一方先置空
        /// 设置SetTextFont()非空时，会将GetEnglishAndChineseCharFont()对应的值置空
        /// \param fontName 字体文件名或字体名()默认simsun.ttc（（字体文件名需带文件后缀，如simsun.ttc 、 simplex.shx）
        /// \return bool true表示设置成功，否则设置失败
        virtual bool SetTextFont(const std::wstring& fontName) = 0;

        /// \brief 获取默认的字体文件名或字体名
        ///
        /// \return 返回默认的字体文件名或字体名
        virtual const std::wstring& GetTextFont() const = 0;

        /// \brief 设置大字体文件名
        ///
        /// 正常表示大字体时该接口设置的应该是大字体字体文件名（单线体shx，需要加文件后缀.shx），SetFont设置的应该是小字体文件名（单线体shx），例如SetBigFont(L"gbcbig.shx"); SetFont(L"simplex.shx");其中gbcbig及simplex均为文件格式为.shx的字体文件名
        /// 但是该接口不限制仅能设置大字体，也可以设置trueType、小字体（单线体shx）及其它（字体文件名需带文件后缀，如simsun.ttc 、 simplex.shx）
        /// 若acad样式字符串为空，则设置的是缺省的字体，若acad样式字符串非空，则会重置整个文本的字体（bigFontName为空时，则会采用GetFont（）的值覆盖所有字体）
        /// 大字体情况下不支持加粗、斜体
        /// SetTextFont()与SetTextBigFont()可结对使用，SetEnglishAndChineseCharFont()单独使用，在使用的时候建议将另一方先置空
        /// 设置SetTextBigFont()非空时，会将GetEnglishAndChineseCharFont()对应的值置空
        /// \param bigFontName 大字体文件名或字体名，默认为空(即默认为不使用大字体)
        /// \return true表示设置成功，否则设置失败
        virtual bool SetTextBigFont(const std::wstring& fontName) = 0;

        /// \brief 获取默认的大字体文件名或字体名
        ///
        /// \return 返回默认的大字体文件名或字体名
        virtual const std::wstring& GetTextBigFont() const = 0;

        /// \breif 设置单元格文字行间距系数
        ///
        /// 行间距是指上一行文字的顶部与下一行顶部之间的距离。
        /// 行间距系数是指行间距的一个倍数关系，如需要设置单倍行距时，其行间距系数为1.0。
        /// 若在SetAcadStyleString之前调用该接口，则设置的是缺省的行间距系数
        /// 若在SetAcadStyleString之后调用该接口，则会重置整个文字的行间距系数
        /// \param lineSpaceScale 待设置的行间距系数值
        /// \return true表示设置成功，否则设置失败
        virtual bool SetTextLineSpaceScale(double lineSpaceScale) = 0;

        /// \breif 获取单元格文字行间距系数
        ///
        /// 该比例为行间距与该行字高最大值的比例
        /// \return 返回单元格文字行间距系数
        virtual double GetTextLineSpaceScale() const = 0;

        /// \biref 设置默认的字符间距
        ///
        /// 若在SetAcadStyleString之前调用该接口，则设置的是缺省的字符间距；
        /// 若在SetAcadStyleString之后调用该接口，则会重置整个文字的字符间距。
        /// \param characterSpace 字符间距，characterSpace应为大于0.75的值
        /// \return ture表示设置成功，否则设置失败
        virtual bool SetCharacterSpace(double characterSpace) = 0;

        /// \brief 获取默认的字符间距
        ///
        /// \return 默认的字符间距
        virtual double GetCharacterSpace() const = 0;

        /// \brief 设置字符的宽度因子
        ///
        /// 若在SetAcadStyleString之前调用该接口，则设置的是缺省的宽度因子；
        /// 若在SetAcadStyleString之后调用该接口，则会重置整个文字的宽度因子。
        /// \param widthFactor 字符的宽度因子,widthFactor应为大于0的值
        /// \return true 表示成功, false 表示失败
        virtual bool SetCharacterWidthFactor(double widthFactor) = 0;

        /// \brief 获取字符的宽度因子
        ///
        /// \return 字符的宽度因子
        virtual double GetCharacterWidthFactor() const = 0;

        /// \brief 添加需要关联的ElementId
        ///
        /// \param elementId 需要添加关联的ElementId
        /// \return bool true表示添加成功，否则添加失败
        virtual bool AddRelatedElementId(const ElementId& elementId) = 0;

        /// \brief 清除所有关联的ElementId
        ///
        /// \return void
        virtual void ClearRelatedElementIds() = 0;

        /// \brief 移除关联的ElementId
        ///
        /// \param elementId 需要移除的关联ElementId
        /// \return bool true表示移除成功，否则移除失败
        virtual bool RemoveRelatedElementId(const ElementId& elementId) = 0;

        /// \brief 获得所有关联的ElementId
        ///
        /// \return std::set<ElementId> 返回该单元格所有关联的ElementId
        virtual const std::set<ElementId>& GetRelatedElementIds() const = 0;

        /// \brief 设置图例参考点位置类型
        ///
        /// \param Type 图例参考点位置类型（具体见定义RelatedElementReferencePointType）
        /// \return bool true表示设置成功，否则失败
        virtual bool SetRelatedElementReferencePointType(RelatedElementReferencePointType Type) = 0;

        /// \brief 获取图例参考点位置类型
        ///
        /// \return RelatedElementReferencePointType 图例参考点位置类型
        virtual RelatedElementReferencePointType GetRelatedElementReferencePointType() const = 0;

        /// \brief 获取表格元素(单元格)所属的表(IDrawingTable)的ElementId
        ///
        /// \return 返回单元格所属的表的ElementId
        virtual ElementId GetDrawingTableElementId() const = 0;

        /// \brief 获取单元格实际的宽
        ///
        /// 默认和GetWidth相同，若该单元格是复合单元格，则实际的宽是同一行所有合并的单元格所在列的列宽的总和
        /// 1.若本身非合并单元格或非合并主单元格（合并范围内最小index的单元格），此时GetWidth与GetRealWidth() 一致
        /// 2.若为合并主单元格，则获取的为合并范围内所有单元格的宽度和
        /// 使用可参照https://km.glodon.com/pages/viewpage.action?pageId=379559666
        /// \return 返回单元格实际的宽
        virtual double GetRealWidth() const = 0;

        /// \brief 获取单元格实际的高
        ///
        /// 默认和GetHeight相同，若该单元格是复合单元格，则实际的高是同一列所有合并的单元格所在行的行高的总和
        /// 1.若本身单元非合并单元格或非合并主单元格（合并范围内最小index的单元格），此时GetHeight与GetRealHeight() 一致
        /// 2.若为合并主单元格，则获取的为合并范围内所有单元格的高度和
        /// 使用可参照https://km.glodon.com/pages/viewpage.action?pageId=379559666
        /// \return 返回单元格实际的高
        virtual double GetRealHeight() const = 0;

        /// \brief 设置单元格边框线的样式ID
        ///
        /// \param styleId 图形样式id
        /// \param nIndex 单元格边的索引(LEFT = 0,TOP = 1,RIGHT = 2, BOTTOM = 3, ALL = -1)
        /// \return bool true 成功，否则失败
        virtual bool SetOutlineStyleId(const ElementId& styleId, int nIndex) = 0;

        /// \brief 获取单元格边框线的样式ID
        ///
        /// \param nIndex 单元格边的索引(LEFT = 0,TOP = 1,RIGHT = 2, BOTTOM = 3)
        /// \return ElementId 样式ID(默认返回左边线样式)
        virtual ElementId GetOutlineStyleId(int nIndex) const = 0;

        /// \brief 设置单元格文字的样式ID
        ///
        /// \param styleId 图形样式id
        virtual bool SetTextStyleId(const ElementId& styleId) = 0;

        /// \brief 获取单元格文字的样式ID
        ///
        /// \return ElementId 样式ID(默认返回左边线样式)
        virtual ElementId GetTextStyleId() const = 0;

        /// \brief 获取单元格最小高度
        ///
        /// \return double 最小高度值
        virtual double GetMinimumHeight() const = 0;

        /// \brief 获取单元格最小宽度
        ///
        /// \return double 最小宽度值
        virtual double GetMinimumWidth() const = 0;

        /// \brief 设置西文及中文字符使用的字体(文件)名
        /// 
        /// \SetTextFont()与SetTextBigFont()可结对使用，SetEnglishAndChineseCharFont()单独使用，在使用的时候建议将另一方先置空
        /// \设置的中西文字体任一非空时，会将GetTextFont()及GetTextBigFont()值置空，且设置的中英文字体会作用到GetText()中序列化
        /// \param englishFontName 英文字符使用的字体文件名或字体名，默认为空（（字体文件名需带文件后缀，如simsun.ttc）
        /// \param chineseFontName 中文字符使用的字体文件名或字体名，默认为空（（字体文件名需带文件后缀，如simsun.ttc）
        /// \return bool true表示设置成功，否则设置失败
        virtual bool SetEnglishAndChineseCharFont(const std::wstring& englishFontName, const std::wstring& chineseFontName) = 0;

        /// \brief 获取西文及中文字符使用的字体(文件)名
        ///
        /// \return 返回西文及中文字符使用的字体(文件)名，pair中first为西文字符字体名，second为中文字符字体名
        virtual std::pair<std::wstring,std::wstring> GetEnglishAndChineseCharFont() const = 0;


        /// \brief 获取是否为合并单元格
        ///
        /// \return 返回是否为合并单元格
        virtual bool IsMerged() const = 0;
    public:
        /// \brief 获取单元格变化通知事件
        ///
        /// \return 返回获取单元格变化通知事件
        static IDrawingTableItemEvent* GetDrawingTableItemEvent();
    };
}



